import { ValidationArguments, ValidatorConstraint, ValidatorConstraintInterface, ValidationOptions, registerDecorator } from 'class-validator';
import { DataSource, Not, ObjectType } from "typeorm";
import { Injectable } from '@nestjs/common';
import * as merge from 'deepmerge';
import { isNil } from 'lodash'

type Condition = {
    entity: ObjectType<any>;
    /**
     * 默认忽略字段为id
     */
    ignore?: string;
    /**
     * 如果没有指定字段则使用当前验证的属性作为查询依据
     */
    property?: string;
};
@ValidatorConstraint({ name: 'dataUniqueExist', async: true })
@Injectable()
export class UniqueExistConstraint implements ValidatorConstraintInterface {
    constructor(
        protected dataSource: DataSource
    ) { }
    async validate(value: any, arg?: ValidationArguments) {
        const config: Omit<Condition, "entity"> = {
            ignore: 'id',
            property: arg.property,

        }
        //先判断entity是否存在
        let condition = ("entity" in arg.constraints[0] ? merge(config, arg.constraints[0]) : {
            ...config,
            entity: arg.constraints[0]
        }) as Required<Condition>
        if (!condition.entity) return false;
        //获取忽视字段的值
        let ignoreValue = (arg as object)[condition.ignore]
        if (ignoreValue == undefined) return false

        let Repo = this.dataSource.getRepository(condition.entity)

        try {
            await Repo.findOne({
                where: {
                    [condition.property]: value,
                    [condition.ignore]: Not(ignoreValue),
                },
                withDeleted: true,
            })
        } catch (error) {
            return false
        }


    }
    defaultMessage(args: ValidationArguments) {
        const { entity, property } = args.constraints[0];
        const queryProperty = property ?? args.property;
        if (!(args.object as any).getManager) {
            return 'getManager function not been found!';
        }
        if (!entity) {
            return 'Model not been specified!';
        }
        return `${queryProperty} of ${entity.name} must been unique!`;
    }
}
export function IsUniqueExist(value: Condition | ObjectType<any>, options: ValidationOptions) {
    return (obj: Record<string, any>, propertyName: string) => {
        registerDecorator({
            target: obj.constructor,
            propertyName,
            constraints: [value],
            validator: UniqueExistConstraint,
            options
        })
    }
}